package com.ruoyi.system.util;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.HttpMethod;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.ruoyi.system.domain.Stock;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class HtmlUtil implements ApplicationListener<ContextClosedEvent> {

    List<WebClient> webClientlist = new ArrayList<>();
    private Integer poolSize = 10;
    private Integer pageCount = 0;

    private LinkedBlockingDeque<Integer> concurrentLinkedQueue = new LinkedBlockingDeque<>();
    private Map<String, WebClient> webClientMap = new ConcurrentHashMap<>();
    private AtomicInteger count = new AtomicInteger();
    ThreadPoolExecutor executor = new ThreadPoolExecutor(
            poolSize,
            poolSize,
            0,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(1024),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());

    //初始化
    public HtmlUtil() {
        for (int i = 0; i < poolSize; i++) {
            WebClient webClient = new WebClient(BrowserVersion.CHROME);//新建一个模拟谷歌Chrome浏览器的浏览器客户端对象

            webClient.getOptions().setThrowExceptionOnScriptError(false);//当JS执行出错的时候是否抛出异常, 这里选择不需要

            webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);//当HTTP的状态非200时是否抛出异常, 这里选择不需要

            webClient.getOptions().setActiveXNative(false);

            webClient.getOptions().setCssEnabled(false);//是否启用CSS, 因为不需要展现页面, 所以不需要启用

            webClient.getOptions().setJavaScriptEnabled(true); //很重要，启用JS。有些网站要开启！

            webClient.setAjaxController(new NicelyResynchronizingAjaxController());//很重要，设置支持AJAX

            webClient.getOptions().setTimeout(30000);

            webClientlist.add(webClient);
        }
    }

    //获取某个url的web客户端
    public String htmlUnitUrl(String url, WebClient webClient) {
        try {
            WebRequest request = new WebRequest(new URL(url), HttpMethod.GET);

            Map additionalHeaders = new HashMap();

            additionalHeaders

                    .put("User-Agent",

                            "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36");

            additionalHeaders.put("Accept-Language", "zh-CN,zh;q=0.8");

            additionalHeaders.put("Accept", "*/*");

            request.setAdditionalHeaders(additionalHeaders);

            // 获取某网站页面
            Page page = webClient.getPage(request);

            return page.getWebResponse().getContentAsString();

        } catch (Exception e) {
        }

        return null;

    }

    CountDownLatch countDownLatch;

    //爬取某网页
    public void work(String url, List<Stock> stockList) {
        try {
            if (url == null) {
                url = "http://q.10jqka.com.cn/";
            }
            for (int i = 0; i < poolSize; i++) {
                HtmlPage page = webClientlist.get(i).getPage(url);//打开网页
            }

            String content1 = htmlUnitUrl(getUrl(1), webClientlist.get(0));
//            String[] split = content1.split("\\[\\[")[1].split("]]")[0].split("\\],\\[");
//            for (String s : split) {
//                String[] split1 = s.split(",");
//
//            }
            pageCount = Integer.parseInt(content1.split("<span class=\"page_info\">1/")[1].split("</span>")[0]);


            for (int i = 1; i <= pageCount; i++) {
//                String content = htmlUnitUrl(getUrl(i), webClientlist.get(0));
//                dealData(content);
                concurrentLinkedQueue.add(i);
            }
            countDownLatch = new CountDownLatch(pageCount);
            try {
                while (concurrentLinkedQueue != null && concurrentLinkedQueue.size() > 0 && !count.equals(pageCount)) {
                    Integer i = concurrentLinkedQueue.take();
                    executor.execute(() -> {
                        String name = Thread.currentThread().getName();
                        getData(i, Integer.parseInt(name.substring(name.length() - 1)), stockList);
                        try {
                            Thread.sleep(2000);
                        } catch (Exception e) {
                        }
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                countDownLatch.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(concurrentLinkedQueue.size());
        } catch (IOException e) {
            e.printStackTrace();

        }

    }


    /**
     * 递归获取队列中数据
     */
    public void getData(Integer index, Integer name, List<Stock> stockList) {
        try {
            /**
             *延迟执行的代码
             */
            String content = htmlUnitUrl(getUrl(index), webClientlist.get(name));

            if (content.contains("Nginx forbidden.")) {
                concurrentLinkedQueue.put(index);
                return;
            } else {
                stockList.addAll(dealData(content));
                countDownLatch.countDown();
//                    writeFile("F://测试//" + index + ".html", content);
                count.incrementAndGet();
            }
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

    public List<Stock> dealData(String content) {
        Integer[] arr = {5, 9, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32};
        String s = content.split("<tbody>")[1].split("</tbody>")[0];
        String[] split = s.split("</tr>");
        List<List<String>> datas = new ArrayList<>();
        int i = 0;
        for (String s1 : split) {
            String[] strings = s1.split(">");
            List<String> data = new ArrayList<>();
            if (i++ > 19) {
                continue;
            }
            for (Integer index : arr) {
                try {
                    String s2 = strings[index].split("<")[0];
                    data.add(s2);
                } catch (Exception e) {
//                    e.printStackTrace();
                }
            }
            datas.add(data);
        }

        return StockUtil.transitionListToStockList(datas);

    }

    /**
     * 返回页码对应连接
     */
    public String getUrl(Integer page) {
        return "http://q.10jqka.com.cn/index/index/board/all/field/zdf/order/desc/page/" + page + "/ajax/1/";
    }

    public String getUrl(String code, String startDate, String endDate) {
        return "http://q.stock.sohu.com/hisHq?code=cn_" + code + "&start=" + startDate + "&end=" + endDate + "&stat=1&order=D&period=d&callback=historySearchHandler&rt=jsonp";
    }


    public static void main(String[] args) {
        HtmlUtil demo = new HtmlUtil();

        String url = "http://q.10jqka.com.cn/";

//        demo.work(url);

    }


    /**
     * 保存抓取的html到本地
     *
     * @param path
     * @param content
     */

    public static boolean writeFile(String path, String content) {
        File file = new File(path);

        boolean isSuccess = true;

        System.out.println(path);

        // if file doesnt exists, then create it

        if (!file.exists()) {
            try {
                isSuccess = file.createNewFile();

            } catch (IOException e) {
                // TODO Auto-generated catch block

                e.printStackTrace();

                isSuccess = false;

            }

        } else {
            file.delete();

        }

        FileWriter fw;

        try {
            fw = new FileWriter(file.getAbsoluteFile());

            BufferedWriter bw = new BufferedWriter(fw);

            bw.write(content);

            bw.close();

            System.out.println("写入成功.");

        } catch (IOException e) {
            // TODO Auto-generated catch block

            e.printStackTrace();

            System.out.println("写入失败.");

            isSuccess = false;

        }

        return isSuccess;

    }


    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
       if(executor ==null){
           return;
       }
       executor.shutdown();
    }
}
